// <copyright file="AdminHttpDiagnostics.cs" company="Colossus Consulting LLC">
// Copyright (c)2003-2010. All Right Reserved.
// </copyright>
// <author>Thomas Carpe</author>
// <email>spark@thomascarpe.com</email>
// <date>2010-03-01</date>
// <summary>TODO: Summary to be provided later.</summary>
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;

using Behemoth.SharePoint.Logging;

namespace Behemoth.SharePoint.WebParts {

  [Guid("20d18218-7a9f-437a-9ccf-ac079b2cb998")]
  public class AdminHttpDiagnostics : Microsoft.SharePoint.WebPartPages.WebPart {

    public AdminHttpDiagnostics() {
      this.ExportMode = WebPartExportMode.All;
    }

    private ErrorBag _errors = new ErrorBag();
    private ULSTraceLogging _log = new ULSTraceLogging();

    #region Web Part Properties

    [Personalizable(PersonalizationScope.Shared)]
    [WebBrowsable(true)]
    [System.ComponentModel.Category("Appearance")]
    [WebDisplayName("Empty Collection Text")]
    [WebDescription("Specifies the text that will be displayed for empty collections.")]
    public string EmptyCollectionText {
      get {
        return _EmptyCollectionText;
      }
      set { _EmptyCollectionText = value; }
    }
    private string _EmptyCollectionText = "The {0} collection is empty.";

    /*
    [Personalizable(PersonalizationScope.Shared)]
    [WebBrowsable(true)]
    [System.ComponentModel.Category("Appearance")]
    [WebDisplayName("Value Cell Width")]
    [WebDescription("Sets the width for the data cell, to force long text to wrap. Set to 0 for no wrapping.")]
    public int ValueCellWidth {
      get {
        return _ValueCellWidth;
      }
      set { _ValueCellWidth = value; }
    }
    private int _ValueCellWidth = 400;
    */

    [Personalizable(PersonalizationScope.Shared)]
    [WebBrowsable(true)]
    [System.ComponentModel.Category("Appearance")]
    [WebDisplayName("Display For Non-Site-Owners")]
    [WebDescription("By default this web part will only display content for site owners. Check the box to allow all users to see content.")]
    public bool DisplayForNonSiteOwners {
      get {
        return _DisplayForNonSiteOwners;
      }
      set { _DisplayForNonSiteOwners = value; }
    }
    private bool _DisplayForNonSiteOwners = false;

    #endregion

    private void RenderNameValueCollection(HtmlTextWriter writer, string title, string groupId, NameValueCollection items, bool drawTableOpen, bool drawTableClose) {
      try {
        if (string.IsNullOrEmpty(groupId)) {
          writer.Write("<div class=\"ms-rteCustom-ArticleTitle AdminHttpDiagnosticsTitle\">" + title + "</div>");
          if (items.Count <= 0) {
            writer.Write("<p>");
            writer.Write(string.Format(EmptyCollectionText, title));
            writer.Write("</p>");
            return;
          }
        }

        if (drawTableOpen) {
          writer.Write("<table width=\"100%\" padding=1 spacing=0 border=0 class=\"ms-listviewtable AdminHttpDiagnosticsData\">");
          writer.Write("<tbody>");
          writer.Write("<tr class=\"ms-viewheader\"><td class=\"ms-vh\">");
          writer.Write("Key");
          writer.Write("</td><td class=\"ms-vh\">");
          writer.Write("Value");
          writer.Write("</td></tr>");
          writer.Write("</tbody>");
        }

        int valueCellWidth = 0; // HACK <-- depricated property
        string wrapStyle = (valueCellWidth <= 0) ? string.Empty : string.Format(" style=\"width: 66%; word-wrap: break-word\"", valueCellWidth);
        string cellClass = (string.IsNullOrEmpty(groupId)) ? "ms-vb" : "ms-vh-group";
        // emulate expanding groups
        if (!string.IsNullOrEmpty(groupId))
          RenderGroupHeader(writer, Page.Server, groupId, title, true, items.Count);
        foreach (string key in items.AllKeys) {
          string value = items[key];
          writer.Write(string.Format("<tr><td class=\"{0}\">", cellClass));
          writer.Write(key);
          writer.Write(string.Format("</td><td class=\"{0}\"", cellClass));
          writer.Write(wrapStyle);
          writer.Write(">");
          writer.Write(Page.Server.HtmlEncode(value));
          writer.Write("</td></tr>");
        }
        if (!string.IsNullOrEmpty(groupId))
          RenderGroupFooter(writer, groupId, true);

        if (drawTableClose)
          writer.Write("</table>");
      } catch (Exception ex) {
        HandleError(string.Format("Exception occurred in RenderNameValueCollection() for Title '{0}'", title), ex, true);
      }
    }

    // TODO move to a toolbox
    #region Group Emulation
    /*
 Example of how grouping works / looks in HTML
<TBODY id="titl1-2_" groupString=""><TR><TD colspan="100" class="ms-gb"  nowrap><img src="/_layouts/images/blank.gif" alt="" height=1 width=0><a href="javascript:" onclick="javascript:ExpCollGroup('1-2_','img_1-2_');return false;"><img id="img_1-2_" src="/_layouts/images/minus.gif" alt="Expand/Collapse" border="0"></a>&nbsp;<a href="javascript:" onclick="javascript:ExpCollGroup('1-2_','img_1-2_');return false;">LocationChoice</a> :&nbsp;Room 1 <span style="font-weight: lighter">&#8206;(2)</span></TD></TR></TBODY>
<TBODY id="tbod1-2__" isLoaded="true">
<TR class="ms-alternating"><td class="ms-vh-group " width=10px><img height=1px width=10px src='/_layouts/images/blank.gif' alt=''></td><TD Class="ms-vb-icon"><IMG border=0 width=16 height=16 SRC="/_layouts/images/blank.gif"></TD><TD Class="ms-vb2"></TD><TD Class="ms-vb-icon"><IMG alt="" border=0 width=16 height=16 SRC="http://spdev/_layouts/images/blank.gif"</TD><TD Class="ms-vb-title" height="100%"><table height="100%" cellspacing=0 class="ms-unselectedtitle" onmouseover="OnItem(this)" CTXName="ctx1" Id="20" Url="/Lists/Events/20_.000" DRef="Lists/Events" Perm="0x7fffffffffffffff" Type="" Ext="" Icon="icgen.gif||" OType="0" COUId="" HCD="" CSrc="" MS="0" CType="Event" CId="0x0102000C2D174614ED454CA6838B09F4CBF679" UIS="512" EventType="0" SUrl=""><tr><td width="100%" Class="ms-vb"><a onfocus="OnLink(this)" href="/Lists/Events/DispForm.aspx?ID=20" ONCLICK="GoToLink(this);return false;" target="_self">Test Event 1<img src="/_layouts/images/blank.gif" class="ms-hidden" border=0 width=1 height=1 alt="Use SHIFT+ENTER to open the menu (new window)."></a><IMG SRC="/_layouts/1033/images/new.gif" alt="New"></td><td><img src="/_layouts/images/blank.gif" width=13 style="visibility:hidden" alt=""></td></tr></table></TD><TD Class="ms-vb2"></TD><TD Class="ms-vb2"><NOBR>3/26/2009 6:00 PM</NOBR></TD><TD Class="ms-vb2"><NOBR>3/26/2009 6:00 PM</NOBR></TD><TD Class="ms-vb2"></TD></TR>
<TR class=""><td class="ms-vh-group " width=10px><img height=1px width=10px src='/_layouts/images/blank.gif' alt=''></td><TD Class="ms-vb-icon"><IMG border=0 width=16 height=16 SRC="/_layouts/images/blank.gif"></TD><TD Class="ms-vb2"></TD><TD Class="ms-vb-icon"><IMG alt="" border=0 width=16 height=16 SRC="http://spdev/_layouts/images/blank.gif"</TD><TD Class="ms-vb-title" height="100%"><table height="100%" cellspacing=0 class="ms-unselectedtitle" onmouseover="OnItem(this)" CTXName="ctx1" Id="21" Url="/Lists/Events/21_.000" DRef="Lists/Events" Perm="0x7fffffffffffffff" Type="" Ext="" Icon="icgen.gif||" OType="0" COUId="" HCD="" CSrc="" MS="0" CType="Event" CId="0x0102000C2D174614ED454CA6838B09F4CBF679" UIS="512" EventType="0" SUrl=""><tr><td width="100%" Class="ms-vb"><a onfocus="OnLink(this)" href="/Lists/Events/DispForm.aspx?ID=21" ONCLICK="GoToLink(this);return false;" target="_self">Test Event 2<img src="/_layouts/images/blank.gif" class="ms-hidden" border=0 width=1 height=1 alt="Use SHIFT+ENTER to open the menu (new window)."></a><IMG SRC="/_layouts/1033/images/new.gif" alt="New"></td><td><img src="/_layouts/images/blank.gif" width=13 style="visibility:hidden" alt=""></td></tr></table></TD><TD Class="ms-vb2"></TD><TD Class="ms-vb2"><NOBR>3/26/2009 6:00 PM</NOBR></TD><TD Class="ms-vb2"><NOBR>3/26/2009 6:00 PM</NOBR></TD><TD Class="ms-vb2"></TD></TR>
</TBODY>
<TBODY id="foot1-2__">       
  */

    private static void RenderGroupHeader(HtmlTextWriter writer, HttpServerUtility server, string groupId, string title, bool loaded, int count) {
      // heading part
      writer.Write("<TBODY id=\"titl{0}\" groupString=\"%3b%23{1}%3b%23\">", groupId, server.UrlEncode(title));
      writer.Write(string.Format("<TR><TD colspan=\"100\" class=\"ms-gb\"  nowrap><img src=\"/_layouts/images/blank.gif\" alt=\"\" height=1 width=0><a href=\"javascript:\" onclick=\"javascript:ExpCollGroup('{0}','img_{0}');return false;\"><img id=\"img_{0}\" src=\"/_layouts/images/minus.gif\" alt=\"Expand/Collapse\" border=\"0\"></a>&nbsp;<a href=\"javascript:\" onclick=\"javascript:ExpCollGroup('{0}','img_{0}');return false;\">Collection</a> :&nbsp;{1} <span style=\"font-weight: lighter\">&#8206;({2})</span></TD></TR>", groupId, title, count));
      writer.Write("</TBODY>");
      // data part
      writer.Write(string.Format("<TBODY id=\"tbod{0}_\" isLoaded=\"{1}\">", groupId, loaded.ToString()));
    }
    private static void RenderGroupFooter(HtmlTextWriter writer, string groupId, bool hide) {
      // data part
      writer.Write("</TBODY>");
      // footer part
      writer.Write(string.Format("<TBODY id=\"foot{0}_\"></TBODY>", groupId));
      if (hide)
        writer.Write(string.Format("<SCRIPT>ExpCollGroup('{0}','img_{0}');</SCRIPT>", groupId));
    }
    #endregion

    protected override void Render(HtmlTextWriter writer) {
      // output any errors, warnings, or info messages that may have been added.
      _errors.Render(writer);
      // if there was an error don't attempt to render the form itself
      if (this._errors.HasErrors)
        return;

      try {
        SPContext ctx = SPContext.Current;
        if (!ctx.Web.UserIsWebAdmin) {
          writer.Write("<p>The diagnostic web part has been added to this page. The Administrator may be testing this page. In future versions, you may be able to use this web part to report problems with this page.</p>");
          return;
        }

        NameValueCollection sv = this.Page.Request.ServerVariables;
        RenderNameValueCollection(writer, "Server Variables", "HttpDiag1-1_", sv, true, false);
        NameValueCollection f = this.Page.Request.Form;
        RenderNameValueCollection(writer, "Form", "HttpDiag1-2_", f, false, false);
        NameValueCollection q = this.Page.Request.QueryString;
        RenderNameValueCollection(writer, "Query String", "HttpDiag1-3_", q, false, false);
        NameValueCollection h = this.Page.Request.Headers;
        RenderNameValueCollection(writer, "HTTP Headers", "HttpDiag1-4_", h, false, true);
        /*
        NameValueCollection c = this.Page.Request.Cookies;
        RenderNameValueCollection(writer, "Cookies", "HttpDiag1-5_", c, false, false);
        */
      } catch (Exception ex) {
        HandleError("Exception occurred in Render()", ex, true);
        // TODO fix this sort of hackish way of outputting the error that may lead to rendering a warning twice
        _errors.Render(writer);
      }
    }

    private void HandleError(string msg, Exception ex, bool isError) {
      if (isError || ex != null) {
        _errors.AddError(msg);
        _errors.AddError(ex);
      } else {
        _errors.AddWarning(msg);
      }
      _log.Write(msg, isError ? TraceSeverity.Unexpected : TraceSeverity.WarningEvent);
      if (ex != null)
        _log.Write(ex);
    }

  } // class
} // namespace
